package com.zan.zanchat.common.common.aspect;

import cn.hutool.core.util.StrUtil;
import com.zan.zanchat.common.common.annotation.RedissonLock;
import com.zan.zanchat.common.common.service.LockService;
import com.zan.zanchat.common.common.utils.SpElUtils;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.lang.reflect.Method;

/**
 * @Author Zan
 * @Create 2024/3/17 15:08
 * @Description :
 */
@Component
@Aspect // 标识是一个切面
@Order(0) // 确保比事务的注解先执行，分布式锁在事务外（非常重要）,即优先加锁，在进行事务，如果锁在事务内，那事务还没提交，锁已经解锁了，相当于锁压根没有用，所以锁要在事务外
public class RedissonLockAspect {

    @Resource
    private LockService lockService;

    @Around(value = "@annotation(redissonLock)")
    public Object around(ProceedingJoinPoint joinPoint, RedissonLock redissonLock) {
        // 获取方法
        Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
        // 获取前缀
        String prefix = StringUtils.isBlank(redissonLock.prefixKey()) ? SpElUtils.getMethodKey(method) : redissonLock.prefixKey();

        String key = SpElUtils.parseSpEl(method, joinPoint.getArgs(), redissonLock.key());
        return lockService.executeWithLock(prefix + ":" + key, redissonLock.waitTime(), redissonLock.unit(), joinPoint::proceed);
    }
}
